package com.bian.spring.framework.context.support;

import com.bian.spring.framework.beans.BeanDefinition;
import com.bian.spring.framework.beans.MutablePropertyValues;
import com.bian.spring.framework.beans.PropertyValue;
import com.bian.spring.framework.beans.factory.support.BeanDefinitionRegistry;
import com.bian.spring.framework.beans.factory.xml.XmlBeanDefinitionReader;
import com.bian.spring.framework.utils.StringUtils;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

/**
 * IOC容器具体的子实现类：
 *      用于加载类路径下的xml格式的配置文件
 *
 * @author bian
 * 2021/01/22
 */
public class ClassPathXmlApplicationContext extends AbstractApplicationContext {

    public ClassPathXmlApplicationContext(String configLocation) {
        this.configLocation = configLocation;
        // 构建解析器对象
        this.beanDefinitionReader = new XmlBeanDefinitionReader();
        try {
            this.refresh();
        } catch (Exception e) {
            throw new RuntimeException("初始化bean出错！");
        }
    }

    @Override
    public Object getBean(String name) throws Exception {
        // 判断对象容器中是否包含指定名称的bean对象，如果包含则直接返回，如果不包含则进行创建
        Object obj = singletonObjects.get(name);
        if (obj != null) {
            return obj;
        }

        // 获取BeanDefinition对象
        BeanDefinitionRegistry registry = beanDefinitionReader.getRegistry();
        BeanDefinition beanDefinition = registry.getBeanDefinition(name);
        // 获取bean信息中的clazzName
        String clazzName = beanDefinition.getClazzName();
        // 通过反射创建对象
        Class<?> clazz = Class.forName(clazzName);
//        Constructor<?> constructor = clazz.getDeclaredConstructor();
//        constructor.setAccessible(true);
//        constructor.newInstance();
        Object beanObj = clazz.newInstance();

        // 依赖注入
        MutablePropertyValues propertyValues = beanDefinition.getPropertyValues();
        for (PropertyValue propertyValue : propertyValues) {
            // 获取name属性值
            String propertyName = propertyValue.getName();
            // 获取value属性
            String value = propertyValue.getValue();
            // 获取ref属性
            String ref = propertyValue.getRef();
            if (ref != null && !"".equals(ref)) {
                // 获取依赖的bean对象
                Object bean = getBean(ref);
                // 拼接方法名
                String methodName = StringUtils.getSetterMethodByFieldName(propertyName);
                // 获取所有的方法对象
                Method[] methods = clazz.getMethods();
                for (Method method : methods) {
                    if (methodName.equals(method.getName())) {
                        // 执行该setter方法
                        method.invoke(beanObj, bean);
                    }
                }
            }

            if (value != null && !"".equals(value)) {
                // 拼接方法名
                String methodName = StringUtils.getSetterMethodByFieldName(propertyName);
                // 获取method对象
                Method method = clazz.getMethod(methodName, String.class);
                method.invoke(beanObj, value);
            }
        }

        // 将beanObj对象保存在singletonObjects容器中
        singletonObjects.put(name, beanObj);
        return beanObj;
    }

    @Override
    public <T> T getBean(String name, Class<? extends T> clazz) throws Exception {
        Object bean = getBean(name);
        return clazz.cast(bean);
    }
}
